<script lang="ts" setup>
import { ref, watch } from "vue";

interface Props {
  modelValue: string | File;
  accept?: string;
}
// 使用泛型约束 props
const props = withDefaults(defineProps<Props>(), {
  accept: "image/png, image/jpeg, image/jpg, image/gif",
});
// 使用泛型约束 emits,
const emit = defineEmits<{
  (e: "update:modelValue", val: File): void;
}>();

// ref: src => Ref<string>
const src = ref(props.modelValue as string);
// template ref: file => Ref(HTMLInputElement | undefined)
const file = ref<HTMLInputElement>();
// watch
watch(
  () => props.modelValue,
  (val) => {
    src.value = val as string;
    file.value!.value = "";
  }
);
// methods
const handleChange = (e: Event) => {
  // 是否选中文件
  const files = (e.target as HTMLInputElement).files;
  // 真值收窄
  if (!files || files.length === 0) {
    return;
  }
  // 读取本地图片并显示
  const reader = new FileReader(),
    file = files[0];
  reader.readAsDataURL(file);
  reader.onload = () => {
    src.value = reader.result as string;
  };
  // 触发事件 update:modelValue 传递文件
  emit("update:modelValue", file);
};
</script>
<template>
  <div
    class="w-24 h-24 rounded-full border-2 shadow-lg overflow-hidden cursor-pointer"
    @click="file?.click()"
  >
    <input
      ref="file"
      type="file"
      class="hidden"
      :accept="accept"
      @change="handleChange"
    />

    <img class="w-full h-full object-cover" :src="src" v-if="src" />
    <slot v-else>
      <svg
        class="p-2"
        fill="none"
        stroke="currentColor"
        stroke-width="1.5"
        viewBox="0 0 24 24"
        xmlns="http://www.w3.org/2000/svg"
        aria-hidden="true"
      >
        <path
          stroke-linecap="round"
          stroke-linejoin="round"
          d="M15.75 6a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0zM4.501 20.118a7.5 7.5 0 0114.998 0A17.933 17.933 0 0112 21.75c-2.676 0-5.216-.584-7.499-1.632z"
        ></path>
      </svg>
    </slot>
  </div>
</template>
